package com.xyhy.core.jackson.utils;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Collection;
import java.util.Map;
import java.util.Objects;

import cn.hutool.core.util.ArrayUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.lang3.StringUtils;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JavaType;
import com.xyhy.core.jackson.JacksonMapper;

import cn.hutool.core.util.StrUtil;

public class JacksonUtil {
  public static ObjectMapper getObjectMapper() {
    return JacksonMapper.instance.objectMapper;
  }

  public static boolean isJson(String str) {
    return isJsonObj(str) || isJsonArray(str);
  }

  public static boolean isJsonObj(String str) {
    if (StrUtil.isBlank(str)) return false;
    return StrUtil.isWrap(str.trim(), '{', '}');
  }

  public static boolean isJsonArray(String str) {
    if (StrUtil.isBlank(str)) return false;
    return StrUtil.isWrap(str.trim(), '[', ']');
  }

  public static String toJson(Object object) {
    if (Objects.isNull(object)) return null;
    if (object instanceof CharSequence) return StrUtil.str((CharSequence) object);

    try {
      return JacksonMapper.instance.objectMapper.writeValueAsString(object);
    } catch (JsonProcessingException e) {
      throw new RuntimeException(e);
    }
  }

  public static JsonNode toJsonNode(Object object) {
    if (Objects.isNull(object)) return null;

    return toJsonNode(toJson(object));
  }

  public static JsonNode toJsonNode(String json) {
    if (StrUtil.isBlank(json)) return null;
    try {
      return getObjectMapper().readTree(json);
    } catch (JsonProcessingException e) {
      throw new RuntimeException(e);
    }
  }

  public static <T> T toBean(String jsonString, Class<T> beanClass) {
    if (StrUtil.isBlank(jsonString)) return null;

    if (beanClass.equals(String.class)) {
      return (T) jsonString;
    }

    try {
      return JacksonMapper.instance.objectMapper.readValue(jsonString, beanClass);
    } catch (JsonProcessingException e) {
      throw new RuntimeException(e);
    }

  }

  public static <T, R> R toBean(T t, Class<R> beanClass) {
    return toBean(toJson(t), beanClass);
  }

  public static <T> T toBean(String jsonString, TypeReference<T> valueTypeRef) {
    if (StringUtils.isEmpty(jsonString)) return null;

    try {
      return JacksonMapper.instance.objectMapper.readValue(jsonString, valueTypeRef);
    } catch (JsonProcessingException e) {
      throw new RuntimeException(e);
    }
  }

  public static <T> T toBean(byte[] bytes, Class<T> beanClass) {
    if (ArrayUtil.isEmpty(bytes)) return null;

    if (beanClass.equals(String.class)) {
      return (T) new String(bytes, StandardCharsets.UTF_8);
    }

    try {
      return JacksonMapper.instance.objectMapper.readValue(bytes, beanClass);
    } catch (IOException e) {
      throw new RuntimeException(e);
    }
  }

  public static <T> T toBean(byte[] bytes, TypeReference<T> valueTypeRef) {
    if (ArrayUtil.isEmpty(bytes)) return null;

    try {
      return JacksonMapper.instance.objectMapper.readValue(bytes, valueTypeRef);
    } catch (IOException e) {
      throw new RuntimeException(e);
    }
  }

  @SuppressWarnings("rawtypes")
  public static <T> Collection<T> toCollection(byte[] bytes, Class<? extends Collection> collectionClass,
                                               Class<T> beanClass) {
    if (ArrayUtil.isEmpty(bytes)) return null;

    try {
      JavaType type = JacksonMapper.instance.objectMapper.getTypeFactory().constructCollectionType(collectionClass,
              beanClass);
      return JacksonMapper.instance.objectMapper.readValue(bytes, type);
    } catch (IOException e) {
      throw new RuntimeException(e);
    }
  }

  @SuppressWarnings("rawtypes")
  public static <T> Collection<T> toCollection(String jsonString, Class<? extends Collection> collectionClass,
                                               Class<T> beanClass) {
    if (StrUtil.isBlank(jsonString)) return null;

    try {
      JavaType type = JacksonMapper.instance.objectMapper.getTypeFactory().constructCollectionType(collectionClass,
              beanClass);
      return JacksonMapper.instance.objectMapper.readValue(jsonString, type);
    } catch (IOException e) {
      throw new RuntimeException(e);
    }
  }

  public static <K, V> Map<K, V> toMap(byte[] bytes, Class<? extends Map<K, V>> mapClass, Class<K> kClass,
                                       Class<V> vClass) {
    if (ArrayUtil.isEmpty(bytes)) return null;

    try {
      JavaType type = JacksonMapper.instance.objectMapper.getTypeFactory().constructMapType(mapClass, kClass, vClass);
      return JacksonMapper.instance.objectMapper.readValue(bytes, type);
    } catch (IOException e) {
      throw new RuntimeException(e);
    }
  }

  public static <K, V> Map<K, V> toMap(String jsonString, Class<? extends Map<K, V>> mapClass, Class<K> kClass,
                                       Class<V> vClass) {
    if (StrUtil.isBlank(jsonString)) return null;

    try {
      JavaType type = JacksonMapper.instance.objectMapper.getTypeFactory().constructMapType(mapClass, kClass, vClass);
      return JacksonMapper.instance.objectMapper.readValue(jsonString, type);
    } catch (JsonProcessingException e) {
      throw new RuntimeException(e);
    }
  }

}
